'use strict';

const authConst = require('../constant/auth-const');
const Controller = require('egg').Controller;

class AdminController extends Controller {

    async doRedis() {
        const { app, ctx } = this;
        const { body } = ctx.request;
        const { event, key, val, time } = body;
        console.log('doRedis:', body);

        try {
            let result = null;
            switch (event) {
                case 'set':
                    result = await app.redis.set(key, val);
                    if (time) {
                        await app.redis.expire(key, time);
                    }
                    break;

                case 'get':
                    result = await app.redis.get(key);
                    break;

                case 'del':
                    result = await app.redis.del(key);
                    break;

                case 'ttl':
                    result = await app.redis.ttl(key);
                    break;

                default:
                    return ctx.errorResult('other event');
            }

            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async initAuthInfo() {
        const { ctx } = this;

        ctx.successResult({
            authType: authConst.authType,
            userType: authConst.userType,
            roleType: authConst.roleType
        });
    }

    async adminRegister() {
        const { ctx, service } = this;
        const { body } = ctx.request;
        const { username, password, type = authConst.userType.admin.value } = body;

        if (!username) {
            return ctx.errorResult('username missing');
        }
        if (!password) {
            return ctx.errorResult('password missing');
        }

        try {
            const userData = {
                username,
                password,
                type
            };
            const result = await service.user.addUserSrv(userData);
            if (result) {
                const { dataValues } = result;
                const { username, password, type, role_id, ...otherData } = dataValues;
                const authToken = ctx.helper.jwtSign({username, type, roleId: role_id});
                let authRouters = [];
                if (type === authConst.userType.supremo.value) {
                    authRouters = await service.roleAuth.getAllAuthRouterSrv();
                } else {
                    authRouters = await service.roleAuth.getRoleAuthRouterSrv(role_id);
                }
                await ctx.helper.setRedisStr(`user:${username}`, authToken, authConst.EXPIRE_TIME);
                ctx.successResult({
                    ...otherData,
                    ...{
                        username,
                        role_id,
                        authToken,
                        authRouters
                    }
                });
            } else {
                ctx.errorResult('admin exist');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async adminLogin() {
        const { ctx, service } = this;
        const { body } = ctx.request;
        const { username, password } = body;

        if (!username) {
            return ctx.errorResult('username missing');
        }
        if (!password) {
            return ctx.errorResult('password missing');
        }

        try {
            const result = await service.user.getUserByPasswordSrv(username, password);
            if (result) {
                const { dataValues } = result;
                const { username, type, role_id } = dataValues;
                const authToken = ctx.helper.jwtSign({username, type, roleId: role_id});
                let authRouters = [];
                if (type === authConst.userType.supremo.value) {
                    authRouters = await service.roleAuth.getAllAuthRouterSrv();
                } else {
                    authRouters = await service.roleAuth.getRoleAuthRouterSrv(role_id);
                }
                await ctx.helper.setRedisStr(`user:${username}`, authToken, authConst.EXPIRE_TIME);
                ctx.successResult({
                    ...dataValues,
                    ...{
                        authToken,
                        authRouters
                    }
                });
            } else {
                ctx.errorResult('no user exist');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async adminLogout() {
        const { ctx, service } = this;
        const { body } = ctx.request;
        const { username } = body;

        if (!username) {
            return ctx.errorResult('username missing');
        }

        try {
            const result = await service.user.getUserSrv({username});
            if (result) {
                await ctx.helper.delRedisStr(`user:${username}`);
                ctx.successResult();
            } else {
                ctx.errorResult('no admin');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async addAdmin() {
        const { ctx, service } = this;
        const { body } = ctx.request;
        const { username, password } = body;

        if (!username) {
            return ctx.errorResult('username missing');
        }
        if (!password) {
            return ctx.errorResult('password missing');
        }

        try {
            const userData = {
                ...body,
                type: authConst.userType.admin.value
            };
            const result = await service.user.addUserSrv(userData);
            if (result) {
                const { dataValues } = result;
                const { password, ...otherData } = dataValues;
                ctx.successResult({
                    ...otherData,
                });
            } else {
                ctx.errorResult('admin exist');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async editAdmin() {
        const { app, ctx, service } = this;
        const data = await service.news.getNewsSrv();
        ctx.successResult(data);
    }

    async getAdmin() {
        const { ctx, service } = this;
        const { userId } = ctx.params;

        if (!userId) {
            return ctx.errorResult('userId missing');
        }

        try {
            const result = await service.user.getUserByIdSrv(userId);
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async getAdminList() {
        const { ctx, service } = this;
        console.log('controller getAdminAll');

        try {
            const result = await service.user.getUserAllSrv();
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async delAdmin() {
        const { app, ctx, service } = this;
        const { userId } = ctx.params;

        if (!userId) {
            return ctx.errorResult('userId missing');
        }

        const result = await service.user.delUserByIdSrv(userId);
        ctx.successResult(result);
    }

    async addRole() {
        const { app, ctx } = this;
        const { body } = ctx.request;
        const { title, type } = body;

        if (!title) {
            return ctx.errorResult('title missing');
        }

        try {
            if (type === authConst.roleType.admin.value) {
                const [result, created] = await app.model.Role.findCreateFind({
                    where: {
                        title
                    },
                    defaults: body
                });

                if (created) {
                    ctx.successResult(result);
                } else {
                    ctx.errorResult('role exist');
                }
            } else {
                const [result, created] = await app.model.Role.findCreateFind({
                    where: {
                        $or: [{title}, {type}]
                    },
                    defaults: body
                });

                if (created) {
                    ctx.successResult(result);
                } else {
                    ctx.errorResult('role exist');
                }
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async editRole() {
        const { app, ctx } = this;
        const { roleId } = ctx.params;
        const { body } = ctx.request;
        const { type, title, desc } = body;

        try {
            const result = await app.model.Role.findOne({
                where: {
                    id: {
                        $ne: roleId
                    },
                    title
                }
            });

            if (result) {
                ctx.errorResult('duplication of title');
            } else {
                const roleResult = await app.model.Role.findOne({
                    where: {
                        id: roleId
                    }
                });

                roleResult.title = title;
                roleResult.desc = desc;
                if (type === authConst.roleType.admin.value) {
                    roleResult.type = type;
                }
                await roleResult.save();
                ctx.successResult(roleResult);
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async getRole() {
        const { app, ctx } = this;
        const { query } = ctx;

        try {
            const result = await app.model.Role.findAll({
                where: {
                    ...query
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async delRole() {
        const { app, ctx, service } = this;
        const { roleId } = ctx.params;

        try {
            const result = await app.model.Role.destroy({
                where: {
                    id: roleId
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async addApiAuth() {
        const { app, ctx, service } = this;
        const { body } = ctx.request;
        const { title, path, func } = body;

        if (!title) {
            return ctx.errorResult('title missing');
        }

        if (!path) {
            return ctx.errorResult('path missing');
        }

        if (!func) {
            return ctx.errorResult('func missing');
        }

        try {
            const [result, created] = await app.model.ApiAuth.findCreateFind({
                where: {
                    title,
                    path,
                    func
                },
                defaults: body
            });

            if (created) {
                ctx.successResult(result);
            } else {
                ctx.errorResult('api exist');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async editApiAuth() {
        const { app, ctx, service } = this;
        const { body } = ctx.request;
        const { apiId } = ctx.params;

        try {
            const result = await app.model.ApiAuth.update(body, {
                where: {
                    id: apiId
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async getApiAuth() {
        const { app, ctx, service } = this;
        const { query } = ctx;

        try {
            const result = await app.model.ApiAuth.findAll({
                where: {
                    ...query
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async delApiAuth() {
        const { app, ctx, service } = this;
        const { apiId } = ctx.params;

        try {
            const result = await app.model.ApiAuth.destroy({
                where: {
                    id: apiId
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async bindUserRole() {
        const { app, ctx, service } = this;
        const { userId } = ctx.params;
        const { body } = ctx.request;
        const { roleId } = body;

        if (!userId) {
            return ctx.errorResult('userId missing');
        }

        if (!roleId) {
            return ctx.errorResult('roleId missing');
        }

        try {
            const result = await app.model.User.update({role_id: roleId}, {
                where: {
                    id: userId
                }
            });

            if (result) {
                ctx.successResult(result);
            } else {
                ctx.errorResult('user no exist');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    /*async bindRoleApi() {
        const { app, ctx, service } = this;
        const { roleId, type } = ctx.query;
        const { body } = ctx.request;
        const { authArray } = body;

        if (!roleId) {
            return ctx.errorResult('roleId missing');
        }

        if (!type) {
            return ctx.errorResult('type missing');
        }

        try {
            const delResult = await app.model.RoleAuth.destroy({
                where: {
                    role_id: roleId,
                    type
                }
            });

            let bindArray = [];
            if (authArray && authArray.length > 0) {
                bindArray = await app.model.RoleAuth.bulkCreate(authArray);
            }

            if (bindArray) {
                ctx.successResult(bindArray);
            } else {
                ctx.errorResult('role already added permission');
            }
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }*/

    async bindRoleApi() {
        const { app, ctx, service } = this;
        const { roleId } = ctx.query;
        const { body } = ctx.request;
        const { type, authArray } = body;

        if (!roleId) {
            return ctx.errorResult('roleId missing');
        }

        if (!type) {
            return ctx.errorResult('type missing');
        }

        try {
            const roleAuthResult = await app.model.RoleAuth.findAll({
                where: {
                    role_id: roleId,
                    type
                }
            });

            for (const itemResult of roleAuthResult) {
                const result = authArray.some(({auth_id, role_id, type}) => (
                    itemResult.role_id === role_id && itemResult.auth_id === auth_id && itemResult.type === type
                ));

                if (!result) {
                    await app.model.RoleAuth.destroy({
                        where: {
                            id: itemResult.id
                        }
                    });
                }
            }

            for (const authItem of authArray) {
                const { auth_id, role_id, type } = authItem;
                const itemResult = await app.model.RoleAuth.findOne({
                    where: {
                        auth_id,
                        role_id,
                        type
                    }
                });

                if (!itemResult) {
                    await app.model.RoleAuth.create({
                        auth_id,
                        role_id,
                        type
                    });
                }
            }

            const result = await app.model.RoleAuth.findAll({
                where: {
                    role_id: roleId,
                    type
                }
            });

            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async unbindRoleAuthById() {
        const { app, ctx, service } = this;
        const { raId } = ctx.params;

        try {
            const result = await app.model.RoleAuth.destroy({
                where: {
                    id: raId
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async unbindRoleAuth() {
        const { app, ctx, service } = this;
        const { query } = ctx;
        const { authId, roleId, type } = query;

        try {
            const result = await app.model.RoleAuth.destroy({
                where: {
                    auth_id: authId,
                    role_id: roleId,
                    type
                }
            });
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async getBindRoleApi() {
        const { ctx, service } = this;
        const { roleId } = ctx.query;

        if (!roleId) {
            return ctx.errorResult('roleId missing');
        }

        try {
            const result = await service.roleAuth.getBindRoleApiSrv(roleId);
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }

    async getUnbindRoleApi() {
        const { ctx, service } = this;
        const { roleId } = ctx.query;

        if (!roleId) {
            return ctx.errorResult('roleId missing');
        }

        try {
            const result = await service.roleAuth.getUnbindRoleApiSrv(roleId);
            ctx.successResult(result);
        } catch (error) {
            ctx.errorResult(error.message);
        }
    }
}

module.exports = AdminController;
